#pragma once

#include "Log.hpp"
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

class Serve
{
public:
    Serve(uint16_t port, std::string ip = "")
        : _port(port)
        , _ip(ip)
        , _sock(-1)
    { }

    // 初始化服务器
    void init()
    {
        // 1. 创建网络套接字
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sock < 0)
        {
            logMessage(FATAL, "%d:%s\n", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "网络套接字创建成功, socket:%d", _sock);

        // 2. 将当前用户给定的ip和port与内核进程相关联
        struct sockaddr_in sock_srv;
        memset(&sock_srv, 0, sizeof(sock_srv));    // 初始化0
        sock_srv.sin_family = AF_INET;    // 网络协议族
        // inet_addr: 本地char*类型字节序，转为4字节网络格式
        sock_srv.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());   
        sock_srv.sin_port = htons(_port);      // 主机格式转为网络格式
        socklen_t len = sizeof(sock_srv);   // 套接字长度
        
        if(bind(_sock, (const struct sockaddr *)&sock_srv, len) < 0)   // 绑定
        {
            logMessage(FATAL, "绑定失败");
            exit(3);
        }
        logMessage(NORMAL, "用户给定的ip和port与内核进程相关联成功!\n");
    }

    // 服务器启动函数
    void start()
    {
        // 0. 服务器程序永不退出
        while(true)
        {
            // 1. 从客户端接受数据，并获取ip及port
            // 1.1 创建输出型参数，接受客户端ip和port
            struct sockaddr_in sock_cli;    // 接受客户端套接字
            memset(&sock_cli, 0, sizeof(sock_cli));   // 初始化0
            socklen_t len = sizeof(sock_cli);    // 套接字长度

            // 1.2 创建缓冲区，读取数据
            char buffer[1024];
            ssize_t n = recvfrom(_sock, (void*)buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&sock_cli, &len);
            // 1.3 输读取的数据及客户端的ip和端口号
            if(n > 0)
            {
                buffer[n] = '\0';   /// 添加末尾'\0'
                // std::string cli_ip = inet_ntoa(sock_cli.sin_addr);    // 将ip转为主机个数const char*
                // uint16_t cli_port = ntohs(sock_cli.sin_addr.s_addr);  // 获取端口号, 网络格式转为主机格式
                // printf("[%s:%d]# %s\n", cli_ip.c_str(), cli_port, buffer);  

                FILE *fp = popen(buffer, "r");
                if(fp == nullptr)
                {
                    logMessage(ERROR, "%d:%s\n", errno, strerror(errno));
                    const char *error_msg = "error command!";
                    sendto(_sock, error_msg, strlen(error_msg), 0, (struct sockaddr *)&sock_cli, len);
                    continue;
                }

                char help[1024];
                std::string res;
                while(fgets(help, 1024, fp) != 0)
                {
                    res += help;
                }
                std::cout << res << std::endl;

                // 2. 将读取到的数据再写回客户端
                sendto(_sock, (void *)buffer, strlen(buffer), 0, (struct sockaddr *)&sock_cli, len);
            }
        }
    }

    ~Serve()
    {
        if(_sock >= 0)
        {
            close(_sock);
        }
    }

private:
    uint16_t _port;     // 端口号
    std::string _ip;   // ip地址
    int _sock;         // 套接字对应文件描述符
};